home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_059 / browser / browser.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  16KB  |  557 lines

  1. /*
  2.  * browser - Rummage around on disks.
  3.  *
  4.  *   copyright (c) 1986, Mike Meyer
  5.  *
  6.  * Permission is hereby granted to distribute this program, so long as this
  7.  * source file is distributed with it, and this copyright notice is not
  8.  * removed from the file.
  9.  *
  10.  * modified Mark Schretlen  86-10-04
  11.  *           last update    87-01-11
  12.  *
  13.  */
  14.  
  15. #include <exec/types.h>
  16. #include <graphics/gfxbase.h>
  17. #include <libraries/dos.h>
  18. #include <libraries/dosextens.h>
  19. #include <intuition/intuition.h>
  20. #include <stdio.h>
  21. #define INTUITION_REV      1L
  22. #define GRAPHICS_REV      1L
  23.  
  24. #define LONGEST_NAME      80   /* Longest file name we can deal with */
  25. #define LONGEST_LINE      256   /* Longest line we will deal with */
  26. #define AVG_LINE_LENGTH      62   /* A guess, tune it if you need to */
  27. #define FILEINFOBLOCKSIZE    256  /* m.e.s.  for memory allocation in Add_Dir */
  28. #define FUDGE                6L  /* A fudge factor for the scroll bar */
  29.  
  30. #define UP_GADGET       0  /* switch flags for Gadget ID */
  31. #define DOWN_GADGET     1
  32. #define SCROLL_GADGET   2
  33. #define NEW_FILE        3
  34.  
  35. #define GWIDTH         14   /* Width of gadget */
  36. #define GHEIGHT         9
  37. struct SpriteImage {
  38.    UWORD posctl[2];
  39.    UWORD sprdata[2][15];
  40.    UWORD reserved[2];
  41.    };
  42.  
  43. #define FIRST 18L
  44.  
  45. /*
  46.  *  Gadget structures put in browser.h
  47.  */
  48.  
  49. #include "browser.h"
  50.  
  51. /*
  52.  *   doggy sprite (M.E.S. 86-10-01)
  53.  */
  54. struct SpriteImage Doggy[34] = {
  55.       0x0002, 0x0002, /* VStart, VStop */
  56.       0x0002, 0x0,
  57.       0x3A02, 0x0,
  58.       0x2A02, 0x1000,
  59.       0xFA02, 0x8000,
  60.       0xF9FE, 0x0,
  61.       0xFFFE, 0x0,
  62.       0x1FFE, 0x0,
  63.       0x1FFE, 0x0,
  64.       0x1FFC, 0x0,
  65.       0x1FFC, 0x0,
  66.       0x0A14, 0x0,
  67.       0x0A14, 0x0,
  68.       0x0A14, 0x0,
  69.       0x0A14, 0x0,
  70.       0x0A14, 0x0,
  71.       0x0000, 0x0000 }; /* End of Sprite */
  72. /*
  73.  * Now, the window for it all
  74.  */
  75. struct NewWindow New_Window = {
  76.    0, 0, 640, 200,         /* Full screen */
  77.    -1L, -1L,            /* Default pens */
  78.    MENUPICK | CLOSEWINDOW      /* I want to know about menupicks */
  79.    | GADGETUP,         /* Window closes and gadgets */
  80.    ACTIVATE         /* Standard window */
  81.    | SMART_REFRESH | NOCAREREFRESH | SIZEBBOTTOM
  82.    | WINDOWSIZING | WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG,
  83.    &Down_Gadget,         /* Add scroll gadget */
  84.    /*(struct Image *)*/ NULL,
  85.    "Browser 1.2 by Mark Schretlen ;original-Mike Meyer;scroll-B.Leivian",   /* Title */
  86.    /*(struct Screen *)*/NULL,
  87.    /*(struct BitMap *)*/NULL,
  88.    100, 57,         /* Minimum sizes */
  89.    640, 200,         /* Maximum sizes */
  90.    WBENCHSCREEN         /* and put it on the workbench */
  91.    } ;
  92.  
  93. /*
  94.  * My very own variables (mostly for done)
  95.  */
  96. struct Window   *My_Window = NULL ;
  97. static FILE      *infile = NULL ;   /* Current input file */
  98. static void      Page_File(unsigned short) ;
  99.  
  100. /* file statistics  M.E.S.  87-01-11 */
  101. struct FStatistics *stats;
  102. struct FStatistics fileInformation = { 0L,0L,0L };
  103.  
  104. /*
  105.  * And someone else's variables
  106.  */
  107. struct IntuitionBase   *IntuitionBase ;
  108. struct GfxBase      *GfxBase ;
  109. extern struct Menu   *AutoMenu ;
  110.  
  111. /*
  112.  * Finally, declare the string twiddling functions as voids
  113.  */
  114. void   strcat(char *, char *), strcpy(char *, char *) ,
  115.    strncat(char *, char *, int) ;
  116.  
  117. main() {
  118.    register struct IntuiMessage   *message,*GetMsg(struct MsgPort *);
  119.    register unsigned short      class, code ;
  120.    APTR address;
  121.    USHORT gadID;
  122.  
  123.    /* Set up the world this lives in */
  124.    if ((IntuitionBase = (struct IntuitionBase *)
  125.        OpenLibrary("intuition.library", INTUITION_REV)) == NULL)
  126.       done(20, "can't open intuition library") ;
  127.  
  128.    if ((GfxBase = (struct GfxBase *)
  129.        OpenLibrary("graphics.library", GRAPHICS_REV)) == NULL)
  130.       done(20, "can't open graphics library") ;
  131.  
  132.    /* set up the scroll bar */
  133.    prop.Flags = FREEVERT | AUTOKNOB | KNOBHIT ;
  134.    prop.VertBody = 0x1000;
  135.  
  136.    if ((My_Window = (struct Window *) OpenWindow(&New_Window)) == NULL)
  137.       done(20, "can't open the window") ;
  138.  
  139.    SetAPen(My_Window -> RPort,3) ;   /* Should be default! */
  140.  
  141.    show_message("Pick Disk with Menu Button ");
  142.  
  143.    /* Set up the first menu level */
  144.    Menu_Init() ;
  145.    Menu_Add("disks ", 1L) ;
  146.    Menu_Item_Add("df0:", ITEMENABLED, 0L, 0) ;
  147.    Menu_Item_Add("df1:", ITEMENABLED, 0L, 0) ;
  148.    Menu_Item_Add("df2:", ITEMENABLED, 0L, 0) ;
  149.    Menu_Item_Add("DH0:", ITEMENABLED, 0L, 0) ;
  150.    Menu_Item_Add("RAM:", ITEMENABLED, 0L, 0) ;
  151.    Menu_Item_Add("VDK:", ITEMENABLED, 0L, 0) ;
  152.    SetMenuStrip(My_Window, AutoMenu) ;
  153.  
  154.    SetPointer(My_Window, Doggy,15,16,0,-4);
  155.  
  156.    /* Now spin on messages, handling them as they arrive */
  157.    for (;;) {
  158.       Wait(1L << (long) My_Window -> UserPort -> mp_SigBit) ;
  159.       while (message = GetMsg(My_Window -> UserPort)) {
  160.          class = message -> Class ;
  161.          code = message -> Code ;
  162.          address = message -> IAddress;
  163.          ReplyMsg(message) ;
  164.          switch (class) {
  165.             case CLOSEWINDOW:
  166.                done(0, NULL) ;
  167.  
  168.             case MENUPICK:
  169.                if (code != MENUNULL)
  170.                   Examine_Menu_Pick(code) ;
  171.                break ;
  172.  
  173.             case GADGETUP:
  174.                gadID = ((struct Gadget *)address) -> GadgetID;
  175.                Page_File(gadID);
  176.                break ;
  177.  
  178.             default:
  179.                printf("browser: intuition event 0x%x\n", class) ;
  180.                done(20, "unexpected intution event") ;
  181.                break ;
  182.             }
  183.          }
  184.       }
  185.    done(20, "broke out of never-breaking loop!") ;
  186. }
  187.  
  188.  
  189. /*
  190.  * Examine_Menu_Pick - takes a menu pick, and twiddles the state variables
  191.  *   to match that pick.
  192.  */
  193. static
  194. Examine_Menu_Pick(Menu_Number)
  195. unsigned short Menu_Number; 
  196. {
  197.    register unsigned short   level, i, dirp ;
  198.    register char      *cp ;
  199.    char         *name, *strchr(char *,int) ;
  200.    struct MenuItem      *ItemAddress(struct Menu *, unsigned short) ;
  201.    /* State variables that describe the current directory */
  202.    static char      Dir_Name[LONGEST_NAME] ;
  203.    static unsigned short   Menu_Level = 0 ;
  204.  
  205.    name = ((struct IntuiText *)
  206.       (ItemAddress(AutoMenu,Menu_Number) -> ItemFill)) -> IText ;
  207.    level = MENUNUM(Menu_Number) ;
  208.  
  209.    /* Got what we want, so clear the menu to avoid confusing the user */
  210.    ClearMenuStrip(My_Window);
  211.    OffGadget((APTR)&Scroll_Gadget, My_Window, NULL);
  212.    OffGadget((APTR)&Up_Gadget, My_Window,NULL);
  213.    OffGadget((APTR)&Down_Gadget, My_Window,NULL);
  214.  
  215.    SetWindowTitles(My_Window,"Browser 1.2 by Mark Schretlen (original by Mike Meyer) ",-1);
  216.  
  217.    /* set dirp to FALSE if the name is not a directory or disk */
  218.    dirp = (strchr(name, '/') != NULL || strchr(name, ':') != NULL) ;
  219.  
  220.    /* First, set the directory name right */
  221.    if (level > Menu_Level)         /* Not possible, die */
  222.       done(20, "impossible menu value returned") ;
  223.    else if (level == 0)         /* picked a new disk */
  224.       Dir_Name[0] = '\0' ;
  225.    else if (level < Menu_Level) {      /* Throw away some levels */
  226.       for (i = 1, cp = strchr(Dir_Name, ':'); i < level; i++) {
  227.          if (cp == NULL) done(20, "broken file name") ;
  228.          cp = strchr(cp, '/') ;
  229.       }
  230.       if (cp == NULL) done(20, "broken file name") ;
  231.       *++cp = '\0' ;
  232.    }
  233.    /* else Menu_Level == level, chose a file at current level */
  234.  
  235.    /* Now, fix up the menu and it's state variable */
  236.    while (Menu_Level > level) {
  237.       Menu_Level-- ;
  238.       Menu_Pop() ;
  239.    }
  240.  
  241.    /* If we added a directory, tack it onto the name */
  242.    if (dirp) {
  243.       Menu_Level++ ;
  244.       strncat(Dir_Name, name,   LONGEST_NAME - strlen(Dir_Name) - 1) ;
  245.    }
  246.  
  247.    /* Now, tell the user all about it */
  248.    if (dirp)
  249.       Add_Dir(Dir_Name, name) ;
  250.    else
  251.       Display_File(Dir_Name, name) ;
  252.    SetMenuStrip(My_Window, AutoMenu) ;
  253. }
  254.  
  255. /*
  256.  * Add_Dir - given a dir and a name, add the menu name with the files in
  257.  *   dir as entries.
  258.  */
  259. static
  260. Add_Dir(dir, name) char *dir, *name; {
  261.    struct FileInfoBlock     *File_Info ;
  262.    register char         *last_char ;
  263.    register struct FileLock   *my_lock, *Lock(char *, int) ;
  264.    unsigned short         count ;
  265.    static char         Name_Buf[LONGEST_NAME] ;
  266.  
  267.    File_Info = (struct FileInfoBlock *)AllocMem(FILEINFOBLOCKSIZE,0);
  268.  
  269.    /* Fix up the trailing / if it needs it */
  270.    last_char = &dir[strlen(dir) - 1] ;
  271.    if (*last_char == '/') *last_char = '\0' ;
  272.  
  273.    /* Now, start on the directory */
  274.    if ((my_lock = Lock(dir, ACCESS_READ)) == NULL) {
  275.       done(20, "can't get lock on file") ;
  276.    }
  277.  
  278.    if (!Examine(my_lock, File_Info)) done(20, "can't examine file") ;
  279.    if (File_Info -> fib_DirEntryType < 0)
  280.       done(20, "Add_Dir called with a non-directory") ;
  281.  
  282.    Menu_Add(name, TRUE) ;
  283.  
  284.    SetAPen(My_Window -> RPort,3) ;
  285.    show_message("Loading Directory          ");
  286.  
  287.    for (ExNext(my_lock, File_Info), count = 0;
  288.         IoErr() != ERROR_NO_MORE_ENTRIES;
  289.         ExNext(my_lock, File_Info), count++)
  290.       if (File_Info -> fib_DirEntryType < 0)
  291.          /* file */
  292.          Menu_Item_Add(File_Info -> fib_FileName, ITEMENABLED, 0L, 0) ;
  293.       else {
  294.          /* directory */
  295.          strcpy(Name_Buf, File_Info -> fib_FileName) ;
  296.          strcat(Name_Buf, "/");
  297.          Menu_Item_Add(Name_Buf, ITEMENABLED, 0L, 0) ;
  298.       }
  299.    if (count == 0) Menu_Item_Add("EMPTY", 0L, 0L, 0) ;
  300.  
  301.    show_message("Directory Available         ");
  302.  
  303.    /* Put everything back */
  304.    if (*last_char == '\0') *last_char = '/' ;
  305.    FreeMem(File_Info,FILEINFOBLOCKSIZE);
  306.    UnLock(my_lock) ;
  307. }
  308.  
  309. /*
  310.  * Display_File - given a directory path and file name, put the first page of
  311.  *   the file in the window.
  312.  */
  313.  
  314. long aprox_lines,file_size;
  315. static long Page_Length = 22L;
  316.  
  317. static
  318. Display_File(dir, name)
  319. char *dir, *name;
  320. {
  321.    static char   File_Name[LONGEST_NAME];
  322.    FILE *fopen();
  323.    long ftell();
  324.    long i,pages;
  325.    extern char *ChangeToString();
  326.    extern FILE *parsefile();
  327.    extern struct FStatistics *stats,fileInformation;
  328.    char *num_of_lines,*num_of_bites;
  329.  
  330.    stats = &fileInformation;
  331.    /* Get the file name */
  332.    strcpy(File_Name, dir);
  333.    strcat(File_Name, name);
  334.  
  335.    if (infile != NULL)
  336.       fclose(infile);
  337.  
  338.    if ((infile = fopen(File_Name, "r")) == NULL) {
  339. #ifdef   DEBUG
  340.       printf("Can't open File: %s\n", File_Name) ;
  341. #endif
  342.       done(20, "can't open file") ;
  343.    }
  344.  
  345.    /* set up the prop gadget for scrolling */
  346.    infile = parsefile(infile);
  347.    aprox_lines = stats->lines;
  348.    file_size = stats->bites;
  349.  
  350.    prop.Flags = FREEVERT | AUTOKNOB;
  351.    if (Page_Length >= aprox_lines)
  352.       i = 0xFFFF;
  353.    else
  354.       {
  355.       pages = aprox_lines/Page_Length;
  356.       if (aprox_lines%Page_Length != 0) pages++;
  357.       i =  0xFFFF / pages;                  /* FFFF=100% - 0000=0% */
  358.       }
  359.    prop.VertBody = i;
  360.    prop.VertPot = 0L;
  361.    fseek(infile, 0L, 0);
  362.  
  363.  
  364.    if (Page_Length < aprox_lines)
  365.       {
  366.          OnGadget((APTR)&Down_Gadget,My_Window,NULL);
  367.          OnGadget((APTR)&Up_Gadget,My_Window,NULL);
  368.             /* enable the scroll bar */
  369.          OnGadget((APTR)&Scroll_Gadget, My_Window, NULL);
  370.       }
  371.  
  372.    SetWindowTitles(My_Window,"Browser 1.2   **** To page, hit appropriate arrow gadget. ****",-1);
  373.    Move(My_Window->RPort,FIRST + 5L ,(long)(My_Window->Height - 5L));
  374.    Text(My_Window->RPort,"                                              ",45L);
  375.    Move(My_Window->RPort,FIRST + 5L ,(long)(My_Window->Height - 5L));
  376.    SetAPen(My_Window->RPort,3);
  377. /*   SetSoftStyle(My_Window->RPort, FSF_UNDERLINED,255); */
  378.    Text(My_Window->RPort,name,(long)strlen(name));
  379.    Text(My_Window->RPort,"     ",3L);
  380.    num_of_bites = ChangeToString(file_size);
  381.    Text(My_Window->RPort,num_of_bites,(long)strlen(num_of_bites));
  382.    Text(My_Window->RPort," bytes",6L);
  383.    Text(My_Window->RPort,"     ",3L);
  384.    num_of_lines = ChangeToString(aprox_lines);
  385.    Text(My_Window->RPort,num_of_lines,(long)strlen(num_of_lines));
  386.    Text(My_Window->RPort," lines",6L);
  387.  
  388.    SetAPen(My_Window->RPort,1);
  389. /*   SetSoftStyle(My_Window->RPort, FS_NORMAL,255);       */
  390.  
  391.    Move(My_Window->RPort,FIRST,17L);
  392.  
  393.    Page_File((USHORT)NEW_FILE);      /* Down from page 0 */
  394. }
  395.  
  396. /*
  397.  * Page_File - move the file up or down one "page"
  398.  */
  399. static void
  400. Page_File(direction) 
  401. USHORT direction;
  402. {
  403.    long where;
  404.    static char   buffer[LONGEST_LINE];
  405.    static char edited[84]; /* allow room for a tab at end */
  406.    static long old_pos;
  407.    static long bites_this_page;
  408.    static long next_page;
  409.    static long size;
  410.    int end_flag = 0;
  411.    long  Line_Length;
  412.    int i,j;
  413.    long new_pos;
  414.    char *p;
  415.  
  416.    if (infile == NULL) return ;
  417.  
  418.    Page_Length = ((My_Window -> Height) - 20) / 8 ;
  419.    Line_Length = (My_Window -> Width - (3+FIRST)) / 8;
  420.  
  421.    switch(direction)
  422.       {
  423.          case UP_GADGET:
  424.             new_pos = old_pos;
  425.             old_pos = 1L;
  426.             break;
  427.          case DOWN_GADGET:
  428.             new_pos = next_page;
  429.             break;
  430.          case SCROLL_GADGET:
  431.              /* compute new position based on the users scroll bar pot */
  432.             new_pos = (file_size * prop.VertPot) / 0xFFFF;
  433.             break;
  434.          case NEW_FILE:
  435.             bites_this_page = 0L;
  436.             next_page = 0L;
  437.             new_pos = 0L;
  438.             old_pos = 1L;
  439.             size = 0L;
  440.             break;
  441.       }
  442.  
  443.  
  444.  
  445.       if (new_pos < 0) new_pos = 0L;
  446.  
  447.       /* if past end of file, back up approx 1/2 page */
  448.       if (new_pos > file_size)
  449.          new_pos = file_size - (bites_this_page / 2);
  450.  
  451.       if ( new_pos == old_pos )  return;   /* no change */
  452.  
  453.       where = (new_pos * 0xFFFF)/file_size ;
  454.       ModifyProp(&Scroll_Gadget,My_Window,NULL,prop.Flags,0,where,0,prop.VertBody);
  455.  
  456.       old_pos = (new_pos + (size +2)) - bites_this_page ;  /* backup one page */
  457.       bites_this_page = 0L;
  458.  
  459.       fseek(infile, new_pos, 0);
  460.  
  461.       /* discard a partial line */
  462.       if (new_pos)
  463.          fgets(buffer, LONGEST_LINE, infile);
  464.  
  465.    /* now put out one page's worth of the file's data */
  466.  
  467.  
  468.    for (where = 17L, j = Page_Length; j--; where = where + 8L)
  469.    {
  470.       Move(My_Window -> RPort,FIRST,where ) ;
  471.  
  472.       /* blank the buffer first */
  473.       for (i = 0; i < 80; i++)
  474.          edited[i] = ' ';
  475.  
  476.       if (!end_flag)
  477.        {
  478.          if (fgets(buffer, LONGEST_LINE, infile) == NULL) 
  479.             end_flag = TRUE;
  480.          else
  481.           {
  482.             size = strlen(buffer);
  483.             bites_this_page = size + bites_this_page;
  484.  
  485.             /* remove the newline */
  486.             buffer[size-1] = '\0';
  487.             size--;
  488.  
  489.             p = buffer;
  490.             size = 0;
  491.  
  492.             /* edit the buffer for tabs and non-printables */
  493.             while(*p)
  494.               {
  495.                 if (*p == '\t')
  496.                   {
  497.                     do {
  498.                          edited[size++] = ' ';
  499.                        } while(size&3);
  500.                   }
  501.                 else if(*p < ' ')
  502.                       {
  503.                         edited[size++] = '^';
  504.                         edited[size++] = *p + '@';
  505.                       } else 
  506.                           edited[size++] = *p;
  507.  
  508.                 p++;
  509.  
  510.                 /* mark the line as longer than the window */
  511.                 if (size >= Line_Length)
  512.                  {
  513.                    edited[size-1] = '>';
  514.                    break;
  515.                  }
  516.               }
  517.           }
  518.        }
  519.       Text(My_Window -> RPort, edited, Line_Length);
  520.    } /* for 1 page to size of window */
  521.    next_page = (bites_this_page + new_pos) - (size + 2);
  522.    return;
  523. }
  524.  
  525. /*
  526.  * done - just close everything that's open, and exit.
  527.  */
  528. static
  529. done(how, why)
  530. int how;
  531. char *why; 
  532. {
  533.  
  534.    if (My_Window) {
  535.       ClearMenuStrip(My_Window) ;
  536.       Menu_Clear() ;
  537.       CloseWindow(My_Window) ;
  538.    }
  539.    if (GfxBase) CloseLibrary(GfxBase) ;
  540.    if (IntuitionBase) CloseLibrary(IntuitionBase) ;
  541.    if (infile) fclose(infile) ;
  542.  
  543.    if (why)
  544.       printf("browser: %s\n", why) ;
  545.    (void) OpenWorkBench() ;
  546.    exit(how) ;
  547. }
  548.  
  549. show_message(s)
  550. char *s;
  551. {
  552.    Move(My_Window -> RPort, FIRST, 17L);
  553.    Text(My_Window -> RPort, s, (long) strlen(s));
  554.    Move(My_Window -> RPort, FIRST, 25L);
  555.    Text(My_Window -> RPort, "                    ", 20L);
  556. }
  557.